package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.article.dto.ArticleStreamMessage;
import com.heima.article.entity.ApArticle;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IComputeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class ComputeServiceImpl implements IComputeService {
    @Override
    public void compute() {

    }

    @Override
    public void update(ArticleStreamMessage message) {

    }

  /*  @Autowired
    private IApArticleService articleService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void compute() {
        // 查询前5天的文章数据  每天凌晨一点执行定时任务,从当天的0点往前推5天
        Date now = new Date();
        Date to = new Date(now.getYear(), now.getMonth(), now.getDate());
        Date from = new Date(to.getTime() - 5 * 24 * 60 * 60 * 1000);
        LambdaQueryWrapper<ApArticle> query = new LambdaQueryWrapper<>();
        query.ge(ApArticle::getPublishTime, from);
        query.lt(ApArticle::getPublishTime, to);
        List<ApArticle> list = articleService.list(query);
        for (ApArticle article : list) {
            // 计算文章分值
            double score = computeScore(article);
            // 缓存文章的分值数据到redis中  首页+频道
            // 按照排名从redis中找到分值高的数据 使用zset存储数据
            // 定义首页的key
            String firstKey = "hot_article_first_page_0";
            // 将文章数据和分值存入redis
            // 将不变的并且前端列表用到的字段数据作为value
            ApArticle toCache = new ApArticle();
            toCache.setId(article.getId());
            toCache.setTitle(article.getTitle());
            toCache.setImages(article.getImages());
            toCache.setAuthorId(article.getAuthorId());
            toCache.setAuthorName(article.getAuthorName());
            toCache.setChannelId(article.getChannelId());
            toCache.setChannelName(article.getChannelName());
            toCache.setPublishTime(article.getPublishTime());
            toCache.setCreatedTime(article.getCreatedTime());

            String value = JSON.toJSONString(toCache);
            redisTemplate.opsForZSet().add(firstKey, value, score);
            // 设置有效期 实际时间比24小时小一点
            redisTemplate.expire(firstKey, 24 * 60 - 1, TimeUnit.MINUTES);
            // 定义频道的key
            String channelKey = "hot_article_first_page_" + article.getChannelId();
            redisTemplate.opsForZSet().add(channelKey, value, score);
            redisTemplate.expire(channelKey, 24 * 60 - 1, TimeUnit.MINUTES);
        }

    }

    @Override
    public void update(ArticleStreamMessage message) {
        // 计算本次聚合操作文章的增量分值
        double scorePlus = computeScore(message);
        // 判断这篇文章是否在redis中已经存在缓存记录
        ApArticle article = articleService.getById(message.getArticleId());
        // 将不变的并且前端列表用到的字段数据作为value
        ApArticle toCache = new ApArticle();
        toCache.setId(article.getId());
        toCache.setTitle(article.getTitle());
        toCache.setImages(article.getImages());
        toCache.setAuthorId(article.getAuthorId());
        toCache.setAuthorName(article.getAuthorName());
        toCache.setChannelId(article.getChannelId());
        toCache.setChannelName(article.getChannelName());
        toCache.setPublishTime(article.getPublishTime());
        toCache.setCreatedTime(article.getCreatedTime());

        String value = JSON.toJSONString(toCache);
        String firstKey = "hot_article_first_page_0";
        Double score = redisTemplate.opsForZSet().score(firstKey, value);
        if (score != null) {
            // 存在的话加上当天的增量分值
            redisTemplate.opsForZSet().incrementScore(firstKey, value, scorePlus);
        } else {
            // 不存在的话先按历史分值计算文章之前的分值,再加上当天的分值,在redis中新增记录
            double scoreHistory = computeScore(article);
            redisTemplate.opsForZSet().add(firstKey, value, scoreHistory + scorePlus);
        }
        // 更新每个频道的数据
        String channelKey = "hot_article_first_page_" + article.getChannelId();
        Double scoreChannel = redisTemplate.opsForZSet().score(channelKey, value);
        if (scoreChannel != null) {
            // 存在的话加上当天的增量分值
            redisTemplate.opsForZSet().incrementScore(channelKey, value, scorePlus);
        } else {
            // 不存在的话先按历史分值计算文章之前的分值,再加上当天的分值,在redis中新增记录
            double scoreHistory = computeScore(article);
            redisTemplate.opsForZSet().add(channelKey, value, scoreHistory + scorePlus);
        }

        // 更新文章表中的数据
        LambdaUpdateWrapper<ApArticle> update = new LambdaUpdateWrapper<>();
        update.eq(ApArticle::getId, article.getId());

        // 这种更新在高并发的场景下可能出现数据不一致问题
        // update.set(ApArticle::getViews, article.getViews() + message.getView());

        // 直接使用sql更新
        // 一条sql语句本身就是一个事务
        // update ap_article set views = views + ?,likes = likes +?,comment = comment +?,collection = collection +? where id = ?
        update.setSql(" views = views +" + message.getView());
        update.setSql(" likes = likes +" + message.getLike());
        update.setSql(" comment = comment +" + message.getComment());
        update.setSql(" collection = collection +" + message.getCollect());
        articleService.update(update);
    }

    *//**
     * 计算文章当日的增量分值
     *
     * @param message
     * @return
     *//*
    private double computeScore(ArticleStreamMessage message) {
        double score = 0;
        score += message.getView() * 1 * 3;
        score += message.getLike() * 3 * 3;
        score += message.getComment() * 5 * 3;
        score += message.getCollect() * 8 * 3;
        return score;
    }

    *//**
     * 计算文章分值
     *
     * @param article
     * @return
     *//*
    private double computeScore(ApArticle article) {
        double score = 0;
        if (article.getViews() != null) {
            score += article.getViews() * 1;
        }
        if (article.getLikes() != null) {
            score += article.getLikes() * 3;
        }
        if (article.getComment() != null) {
            score += article.getComment() * 5;
        }
        if (article.getCollection() != null) {
            score += article.getCollection() * 8;
        }
        return score;
    }*/
}
